package com.aplink.generic.xmlparser;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.content.Context;
import android.content.res.Resources;
import android.text.TextUtils;

import com.aplink.generic.GenericApplication;
import com.aplink.generic.util.ResourcesHelper;

public class XmlPaserUtil {

	private static Document buildDocument(final InputStream istream)
	        throws ParserConfigurationException, SAXException, IOException {
		final InputSource isource = new InputSource(new InputStreamReader(
		        istream, "UTF-8"));
		final DocumentBuilderFactory dbFactory = DocumentBuilderFactory
		        .newInstance();
		final DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
		final Document doc = dBuilder.parse(isource);
		doc.getDocumentElement().normalize();
		return doc;
	}

	public static String getAttrValue(final Node node, final String attrName) {
		final Attr attr = (Attr) node.getAttributes().getNamedItem(attrName);
		if (attr != null) {
			return attr.getValue();
		}
		return null;
	}

	public static String getNodeValue(final Node node) {
		Node child;
		if (node != null) {
			if (node.hasChildNodes()) {
				child = node.getFirstChild();
				while (child != null) {
					if (child.getNodeType() == Node.TEXT_NODE) {
						return child.getNodeValue();
					}
					child = child.getNextSibling();
				}
			}
		}
		return null;
	}

	public static InputStream getXMLInputStream(final int xmlIdFile,
	        Context context) {
		if (xmlIdFile != ResourcesHelper.RESOURCE_NOT_FOUND) {
			return context.getResources().openRawResource(xmlIdFile);
		}
		return null;
	}

	public static boolean isAttributeEqualNo(XmlPullParser parser,
	        String nameSpace, String attributeName) {
		String value = parser.getAttributeValue(nameSpace, attributeName);
		if (TextUtils.isEmpty(value)) {
			return true;
		}
		return value.equalsIgnoreCase("N");
	}

	public static boolean isAttributeEqualYes(XmlPullParser parser,
	        String nameSpace, String attributeName) {
		String value = parser.getAttributeValue(nameSpace, attributeName);
		if (TextUtils.isEmpty(value)) {
			return false;
		}
		return value.equalsIgnoreCase("Y");
	}

	/**
	 * Open XML document from Raw folder
	 * 
	 * @param context
	 * @param xmlIdFile
	 * @return
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 */
	public static Document openDocumentFrom(final int xmlIdFile)
	        throws ParserConfigurationException, SAXException, IOException,
	        Resources.NotFoundException {
		final Context context = GenericApplication.getInstance()
		        .getApplicationContext();
		if (xmlIdFile != ResourcesHelper.RESOURCE_NOT_FOUND) {
			final InputStream istream = context.getResources().openRawResource(
			        xmlIdFile);
			return XmlPaserUtil.buildDocument(istream);
		}
		return null;
	}

	/**
	 * Open XML document from Raw folder
	 * 
	 * @param context
	 * @param xmlIdFile
	 * @return
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 */
	public static Document openDocumentFrom(final int xmlIdFile,
	        final Context context) throws ParserConfigurationException,
	        SAXException, IOException, Resources.NotFoundException {
		final InputStream istream = context.getResources().openRawResource(
		        xmlIdFile);
		return XmlPaserUtil.buildDocument(istream);
	}

	/**
	 * Open XML document from Asset folder.
	 * 
	 * @param context
	 * @param xmlFileName
	 * @return
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 * @throws IOException
	 */
	public static Document openDocumentFrom(String xmlFileName)
	        throws ParserConfigurationException, SAXException, IOException {
		if (!xmlFileName.contains(".xml")) {
			xmlFileName += ".xml";
		}
		final Context context = GenericApplication.getInstance()
		        .getApplicationContext();
		final InputStream istream = context.getAssets().open(xmlFileName);
		return XmlPaserUtil.buildDocument(istream);
	}

	public static String readAttribute(XmlPullParser parser, String nameSpace,
	        String attributeName) {
		String value = parser.getAttributeValue(nameSpace, attributeName);
		if (TextUtils.isEmpty(value)) {
			return null;
		}
		return value;
	}

	public static String readText(XmlPullParser parser) throws IOException,
	        XmlPullParserException {
		String result = "";
		if (parser.next() == XmlPullParser.TEXT) {
			result = parser.getText();
			parser.nextTag();
		}
		return result;
	}

	public static void skip(XmlPullParser parser)
	        throws XmlPullParserException, IOException {
		if (parser.getEventType() != XmlPullParser.START_TAG) {
			throw new IllegalStateException();
		}
		int depth = 1;
		while (depth != 0) {
			switch (parser.next()) {
			case XmlPullParser.END_TAG:
				depth--;
				break;
			case XmlPullParser.START_TAG:
				depth++;
				break;
			}
		}
	}

	public static boolean validateXMLSchema(final String xsdPath,
	        final String xmlPath) {
		try {
			final SchemaFactory factory = SchemaFactory
			        .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
			final Schema schema = factory.newSchema(new File(xsdPath));
			final Validator validator = schema.newValidator();
			validator.validate(new StreamSource(new File(xmlPath)));
		} catch (final IOException e) {
			return false;
		} catch (final SAXException e) {
			return false;
		}
		return true;
	}
}
